package midi;

import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiMessage;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Receiver;
import javax.sound.midi.ShortMessage;
import javax.sound.midi.MidiDevice.Info;

public class MidiManager implements Receiver {

	// private String midiDeviceName = "Microsoft GS Wavetable Synth";
	private String midiDeviceName = "E-MU XMidi2X2";
	private MidiDevice midiDevice = null;
	private int channel = 0;

	private ShortMessage lastReceivedShortMessage = null;

	private ShortMessage message = new ShortMessage();

	public void activate() {
		Info[] midiDevices = MidiSystem.getMidiDeviceInfo();
		for (Info device : midiDevices) {
			System.out.println(device.getName());
			if (this.midiDeviceName.compareTo(device.getName()) == 0) {
				try {
					this.midiDevice = MidiSystem.getMidiDevice(device);
					this.midiDevice.open();
					this.midiDevice.getTransmitter().setReceiver(this);
					// System.out.println("OK Found one for "+
					// this.midiDeviceName +" !");
				} catch (MidiUnavailableException midiUnavailableException) {
					midiUnavailableException.printStackTrace();
				}
			}
		}
	}

	public void stop() {
		if (midiDevice != null) {
			this.midiDevice.close();
		}
	}

	public ShortMessage getLastReceivedShortMessage() {
		return lastReceivedShortMessage;
	}

	public void change(int instrument) {
		if (midiDevice != null) {
			try {
				this.message.setMessage(ShortMessage.PROGRAM_CHANGE, this.channel, instrument, 0);
				this.midiDevice.getReceiver().send(this.message, -1);
			} catch (MidiUnavailableException myMidiUnavailableException) {
				myMidiUnavailableException.printStackTrace();
			} catch (InvalidMidiDataException myInvalidMidiDataException) {
				myInvalidMidiDataException.printStackTrace();
			}
		}
	}

	public void play(Note note) {
		if (midiDevice != null) {
			try {
				this.message.setMessage(ShortMessage.NOTE_ON, this.channel, note.getKey(), note.getVelocity());
				this.midiDevice.getReceiver().send(this.message, -1);
			} catch (MidiUnavailableException myMidiUnavailableException) {
				myMidiUnavailableException.printStackTrace();
			} catch (InvalidMidiDataException myInvalidMidiDataException) {
				myInvalidMidiDataException.printStackTrace();
			}
		}
	}

	public void stop(Note note) {
		if (midiDevice != null) {
			try {
				this.message.setMessage(ShortMessage.NOTE_OFF, this.channel, note.getKey(), 0);
				this.midiDevice.getReceiver().send(this.message, -1);
			} catch (MidiUnavailableException myMidiUnavailableException) {
				myMidiUnavailableException.printStackTrace();
			} catch (InvalidMidiDataException myInvalidMidiDataException) {
				myInvalidMidiDataException.printStackTrace();
			}
		}
	}

	public void setChannel(int channel) {
		this.channel = channel;
	}

	// @Override
	public void close() {

	}

	// @Override
	public void send(MidiMessage message, long timestamp) {
		// System.out.println(message);
		// if (this.managedBeat != null) {
		if (message instanceof ShortMessage) {
			handleShortMessage((ShortMessage) message);
		}
		// }
	}

	public void sendEvent(MidiMessage message, long timestamp) {
		if (midiDevice != null) {
			try {
				this.midiDevice.getReceiver().send(this.message, timestamp);
			} catch (MidiUnavailableException myMidiUnavailableException) {
				myMidiUnavailableException.printStackTrace();
			}
		}
	}

	private void handleShortMessage(ShortMessage message) {
		this.lastReceivedShortMessage = message;
		// if (message.getCommand() != 240) {
		System.out.println("MIDI COMMAND = " + ((ShortMessage) message).getCommand() + ", VALUES = [" + message.getData1() + ", " + message.getData2() + "]");
		switch (message.getCommand()) {
		case ShortMessage.NOTE_ON:
			// this.managedBeat.noteOn(message.getData1(),
			// message.getData2());
			break;
		case ShortMessage.NOTE_OFF:
			// this.managedBeat.noteOff(message.getData1(),
			// message.getData2());
			break;
		default:
			break;
		}
		// }

	}

}
